package com.fanvil.videoconference;

import android.annotation.SuppressLint;
import android.util.Log;
import android.util.Pair;
import android.util.Size;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import com.fanvil.videoconference.FvlLogger;
import com.fanvil.videoconference.FvlSystemProperties;

@SuppressLint("InlinedApi")
public class FvlVideoLayout {
    private static FvlLogger sLogger =
        FvlLogger.getLogger(FvlVideoLayout.class.getSimpleName(), FvlLogger.DEBUG);

    private static final boolean DEBUG = false;

    private static final String VIDEO_CONFIG_FILE = "/data/data/vdroid.server/video_config.txt";

    public static final int VIEW_ROLE_INVALID = -1;
    public static final int VIEW_ROLE_LOCAL = 0;
    public static final int VIEW_ROLE_REMOTE = 1;

    private static final int LANDSCAPE = 0;
    private static final int PORTRAIT = 1;

    private Map<String, Pair<Float, Float>> mMediaSizeRatioMap;

    private static FvlVideoLayout sInstance;

    public static FvlVideoLayout getInstance() {
        if (sInstance == null) {
            sInstance = new FvlVideoLayout();
        }
        return sInstance;
    }

    private FvlVideoLayout() {
        sLogger.i("FvlVideoLayout Created");

        mMediaSizeRatioMap = new HashMap<>();
        loadVideoRatio(VIDEO_CONFIG_FILE);
    }

    public void release() {
        sLogger.i("FvlVideoLayout release");
        if (mMediaSizeRatioMap != null) {
            mMediaSizeRatioMap.clear();
            mMediaSizeRatioMap = null;
        }
    }

    public Pair<Float, Float> getVideoRatio(int viewRole, int viewWidth, int viewHeight, int videoWidth, int videoHeight) {
        float widthRatio = 1.0f;
        float heightRatio = 1.0f;

        if (viewWidth <= 0 || viewHeight <= 0 || videoWidth <= 0 || videoHeight <= 0) {
            sLogger.e("getVideoRatio: invalid size  viewWidth=" + viewWidth + " viewHeight=" + viewHeight
                     + " videoWidth=" + videoWidth + " videoHeight=" + videoHeight);
            return null;
        }

        Size viewSize = new Size(viewWidth, viewHeight);
        Size videoSize = new Size(videoWidth, videoHeight);
        String tag = getTag(viewRole, viewSize, videoSize);
        Pair<Float, Float> calculatedRatio = getCalculatedSizeRatio(viewWidth, viewHeight, videoWidth, videoHeight);
        Pair<Float, Float> correctionRatio = mMediaSizeRatioMap.get(tag);
        Pair<Float, Float> debugRatio = null;
        boolean enableDebugRatio = FvlSystemProperties.get("vendor.video.ratio", "false").equals("true");

        if (correctionRatio != null) {
            sLogger.i("getVideoRatio: Correction Tag="+ tag + " WidthRatio=" + correctionRatio.first + " HeightRatio=" + correctionRatio.second);
            sLogger.i("getVideoRatio: Calculated Tag="+ tag + " WidthRatio=" + calculatedRatio.first + " HeightRatio=" + calculatedRatio.second);
        }

        if (correctionRatio != null) {
            widthRatio = correctionRatio.first;
            heightRatio = correctionRatio.second;
        } else {
            widthRatio = calculatedRatio.first;
            heightRatio = calculatedRatio.second;
        }

        if (enableDebugRatio) {
            debugRatio = getDebugRatio(viewWidth, viewHeight, videoWidth, videoHeight, widthRatio, heightRatio);
            if (debugRatio != null) {
                widthRatio = debugRatio.first;
                heightRatio = debugRatio.second;
            }
        }

        sLogger.i("getVideoRatio: WidthRatio=" + widthRatio + " HeightRatio=" + heightRatio);
        sLogger.i("getVideoRatio: VideoSize=" + videoWidth + "X" + videoHeight);
        sLogger.i("getVideoRatio: ViewSize=" + viewWidth + "X" + viewHeight);
        sLogger.i("getVideoRatio: WidthRatio=" + widthRatio + " HeightRatio=" + heightRatio);

        return new Pair<>(widthRatio, heightRatio);
    }

    private String getTag(int viewRole, int viewWidth, int viewHeight, int videoWidth, int videoHeight) {
        StringBuilder builder = new StringBuilder();
        builder.append(viewRole);
        builder.append('_');
        builder.append(viewWidth);
        builder.append('_');
        builder.append(viewHeight);
        builder.append('_');
        builder.append(videoWidth);
        builder.append('_');
        builder.append(videoHeight);
        return builder.toString();
    }

    private String getTag(int viewWindowType, Size viewSize, Size videoSize) {
        StringBuilder builder = new StringBuilder();
        builder.append(viewWindowType);
        builder.append('_');
        builder.append(viewSize.getWidth());
        builder.append('_');
        builder.append(viewSize.getHeight());
        builder.append('_');
        builder.append(videoSize.getWidth());
        builder.append('_');
        builder.append(videoSize.getHeight());
        return builder.toString();
    }

    private String getTag(int viewWidth, int viewHeight, int videoWidth, int videoHeight) {
        StringBuilder builder = new StringBuilder();
        builder.append(viewWidth);
        builder.append('_');
        builder.append(viewHeight);
        builder.append('_');
        builder.append(videoWidth);
        builder.append('_');
        builder.append(videoHeight);
        return builder.toString();
    }

    private String getTag(Size viewSize, Size videoSize) {
        StringBuilder builder = new StringBuilder();
        builder.append(viewSize.getWidth());
        builder.append('_');
        builder.append(viewSize.getHeight());
        builder.append('_');
        builder.append(videoSize.getWidth());
        builder.append('_');
        builder.append(videoSize.getHeight());
        return builder.toString();
    }

    private Pair<Float, Float> getCalculatedSizeRatio(int viewWidth, int viewHeight, int videoWidth, int videoHeight) {
        float widthRatio = 1.0f;
        float heightRatio = 1.0f;
        float videoRatio = videoWidth/(float)videoHeight;
        float viewRatio = viewWidth/(float)viewHeight;
        sLogger.i("getCalculatedSizeRatio VideoSize=" + videoWidth + "X" + videoHeight + " videoRatio=" + videoRatio);
        sLogger.i("getCalculatedSizeRatio ViewSize=" + viewWidth + "X" + viewHeight + " viewRatio=" + viewRatio);
        if(viewWidth>viewHeight){//Landscape
            if (videoRatio>viewRatio){
                widthRatio = videoRatio/viewRatio;
                sLogger.i("getCalculatedSizeRatio Horizontal WidthRatio1=" + widthRatio);
            } else {
                widthRatio = viewRatio/videoRatio;
                sLogger.i("getCalculatedSizeRatio Horizontal WidthRatio2=" + widthRatio);
            }
        } else {
            if (videoRatio>viewRatio){//Portrait
                heightRatio = videoRatio/viewRatio;
                sLogger.i("getCalculatedSizeRatio Portrait HeightRatio1=" + heightRatio);
            } else {
                heightRatio = viewRatio/videoRatio;
                sLogger.i("getCalculatedSizeRatio Portrait HeightRatio1=" + heightRatio);
            }
        }
        sLogger.i("getCalculatedSizeRatio WidthRatio=" + widthRatio + " HeightRatio=" + heightRatio);
        return new Pair<>(widthRatio, heightRatio);
    }

    private Pair<Float, Float> getDebugRatio(int viewWidth, int viewHeight, int videoWidth, int videoHeight,
            float defaultWidthRatio, float defaultHeightRatio) {
        float widthRatio = 0.0f;
        float heightRatio = 0.0f;
        float videoRatio = videoWidth/(float)videoHeight;
        float viewRatio = viewWidth/(float)viewHeight;
        sLogger.i("getDebugRatio VideoSize=" + videoWidth + "X" + videoHeight + " videoRatio=" + videoRatio);
        sLogger.i("getDebugRatio ViewSize=" + viewWidth + "X" + viewHeight + " videoRatio=" + viewRatio);
        if(viewWidth>viewHeight){//Landscape
            if (videoRatio>viewRatio){
                widthRatio = Float.parseFloat(FvlSystemProperties.get("vendor.video.ratio.l_width1", "0.0f"));
                sLogger.i("getDebugRatio Landscape WidthRatio1  vendor.video.ratio.l_width1=" + widthRatio);
            } else {
                widthRatio = Float.parseFloat(FvlSystemProperties.get("vendor.video.ratio.l_width2", "0.0f"));
                sLogger.i("getDebugRatio Landscape WidthRatio2  vendor.video.ratio.l_width2=" + widthRatio);
            }
        } else {//Portrait
            if (videoRatio>viewRatio){
                heightRatio = Float.parseFloat(FvlSystemProperties.get("vendor.video.ratio.p_height1", "0.0f"));
                sLogger.i("getDebugRatio Portrait HeightRatio1  vendor.video.ratio.p_height1=" + heightRatio);
            } else {
                heightRatio = Float.parseFloat(FvlSystemProperties.get("vendor.video.ratio.p_height2", "0.0f"));
                sLogger.i("getDebugRatio Portrait HeightRatio2  vendor.video.ratio.p_height2=" + heightRatio);
            }
        }
        if (widthRatio == 0.0f) {
            widthRatio = defaultWidthRatio;
            sLogger.i("getDebugRatio DefaultWidthRatio=" + defaultWidthRatio);
        }
        if (heightRatio == 0.0f) {
            heightRatio = defaultHeightRatio;
            sLogger.i("getDebugRatio DefaultHeightRatio=" + defaultHeightRatio);
        }
        sLogger.i("getDebugRatio WidthRatio=" + widthRatio + " HeightRatio=" + heightRatio);
        return new Pair<>(widthRatio, heightRatio);
    }

    private void loadVideoRatio(String filename) {
        sLogger.i("FvlVideoLayout loadVideoRatio=" + filename);
        FileInputStream fstream = null;

        File file = new File(filename);
        if (file == null || !file.exists()) {
            sLogger.i("FvlVideoLayout filename is invalid");
            return;
        }

        try {
            fstream = new FileInputStream(filename);
            DataInputStream in = new DataInputStream(fstream);
            BufferedReader br = new BufferedReader(new InputStreamReader(in));
            String buf;

            while (((buf = br.readLine()) != null)) {
                if (buf.startsWith("#") || buf.length() == 0) {
                    continue;
                }
                String [] parts = buf.split(",");
                String [] pair;
                int viewRole = Integer.parseInt(parts[0]);
                pair = parts[1].split("x");
                int viewWidth = Integer.parseInt(pair[0].trim());
                int viewHeight = Integer.parseInt(pair[1].trim());
                pair = parts[2].split("x");
                int videoWidth = Integer.parseInt(pair[0].trim());
                int videoHeight = Integer.parseInt(pair[1].trim());
                float widthRatio = Float.parseFloat(parts[3]);
                float heightRatio = Float.parseFloat(parts[4]);
                if (DEBUG) {
                    sLogger.i("loadVideoRatio viewRole=" + viewRole +
                            " ViewSize=" + viewWidth + "x" + viewHeight +
                            " VideoSize=" + videoWidth + "x" + videoHeight +
                            " WidthRatio=" + widthRatio + " HeightRatio=" + heightRatio);
                }
                mMediaSizeRatioMap.put(getTag(viewRole, viewWidth, viewHeight, videoWidth, videoHeight), new Pair<>(widthRatio, heightRatio));
            }
        } catch (NumberFormatException | ArrayIndexOutOfBoundsException e) {
            sLogger.e("loadVideoRatio: invalid config content.");
        } catch (IOException ex) {
        } finally {
            if (fstream != null) {
                try {
                    fstream.close();
                } catch (IOException ex) {}
            }
        }

        if (DEBUG) {
            Iterator<Map.Entry<String, Pair<Float, Float>>> iterator =
                    mMediaSizeRatioMap.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry<String, Pair<Float, Float>> next = iterator.next();
                Pair<Float, Float> ratio = next.getValue();
                sLogger.i("MediaSizeRatioMap Tag="+ next.getKey() + " WidthRatio=" + ratio.first + " HeightRatio=" + ratio.second);
            }
        }
    }
}
